<template>
    <transition :name="transitionName">
        <div v-show="visible" class="back-to-ceiling" @click="backToTop">
            <svg width="16" height="16" viewBox="0 0 17 17" xmlns="http://www.w3.org/2000/svg"
                 class="Icon Icon--backToTopArrow" aria-hidden="true" style="height:16px;width:16px">
                <path
                        d="M12.036 15.59a1 1 0 0 1-.997.995H5.032a.996.996 0 0 1-.997-.996V8.584H1.03c-1.1 0-1.36-.633-.578-1.416L7.33.29a1.003 1.003 0 0 1 1.412 0l6.878 6.88c.782.78.523 1.415-.58 1.415h-3.004v7.004z"/>
            </svg>
        </div>
    </transition>
</template>

<script setup lang="ts">
import {reactive, toRefs, onMounted, onBeforeUnmount} from 'vue';

const props = defineProps({
    visibilityHeight: {
        type: Number,
        default: 400
    },
    backPosition: {
        type: Number,
        default: 0
    },
    customStyle: {
        type: Object,
        default: function () {
            return {
                right: '20px',
                bottom: '20px',
                width: '30px',
                height: '30px',
                'border-radius': '4px',
                'line-height': '35px',
                background: '#e7eaf1'
            }
        }
    },
    transitionName: {
        type: String,
        default: 'fade'
    }
});


const state = reactive({
    visible: false,
    isMoving: false,
});


let interval;


function easeInOutQuad(t, b, c, d) {
    if ((t /= d / 2) < 1) return c / 2 * t * t + b
    return -c / 2 * (--t * (t - 2) - 1) + b
}

function handleScroll() {
    state.visible = window.pageYOffset > props.visibilityHeight
}

const backToTop = function () {
    if (state.isMoving) return
    const start = window.pageYOffset
    let i = 0
    state.isMoving = true
    interval = setInterval(() => {
        const next = Math.floor(easeInOutQuad(10 * i, start, -start, 500))
        if (next <= props.backPosition) {
            window.scrollTo(0, props.backPosition)
            clearInterval(interval)
            state.isMoving = false
        } else {
            window.scrollTo(0, next)
        }
        i++
    }, 5)
}

onMounted(() => {
    window.addEventListener('scroll', handleScroll)
})

onBeforeUnmount(() => {
    window.removeEventListener('scroll', handleScroll)
    if (interval) {
        clearInterval(interval)
    }
})

const {visible} = toRefs(state);

</script>

<style scoped>
.back-to-ceiling {
    right: 20px;
    bottom: 20px;
    line-height: 35px;
    background: #fff;
    position: fixed;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    color: #409eff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    box-shadow: 0 0 6px rgba(0, 0, 0, .12);
    cursor: pointer;
    z-index: 5;
}

.back-to-ceiling:hover {
    background: #d5dbe7;
}

.fade-enter-active,
.fade-leave-active {
    transition: opacity .5s;
}

.fade-enter,
.fade-leave-to {
    opacity: 0
}

.back-to-ceiling .Icon {
    fill: #409eff;
    background: none;
}
</style>
